package com.blyat.xsoft.gateway.ribbon;

import com.blyat.xsoft.gateway.ribbon.loadbalancer.rule.DynamicLoadBalanceRule;
import com.blyat.xsoft.gateway.ribbon.loadbalancer.server.DynamicServerList;
import com.blyat.xsoft.gateway.ribbon.loadbalancer.rule.LoadBalancerRuleService;
import com.blyat.xsoft.gateway.ribbon.loadbalancer.server.ServerLoader;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.*;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Auther: syh
 * @Date: 2020/8/27
 * @Description:
 */
public class XSoftLoadBalancerClient extends RibbonLoadBalancerClient {

    private static final Map<String, ILoadBalancer> clientMap = new ConcurrentHashMap<>();

    private SpringClientFactory clientFactory;
    private LoadBalancerRuleService ruleService;
    private ServerLoader serverLoader;

    public XSoftLoadBalancerClient(SpringClientFactory clientFactory) {
        super(clientFactory);
        this.clientFactory = clientFactory;
    }

    @Override
    protected ILoadBalancer getLoadBalancer(String serviceId) {
        ILoadBalancer loadBalancer = clientMap.get(serviceId);
        if (loadBalancer == null) {
            IClientConfig clientConfig = getInstance(serviceId, IClientConfig.class);

            // 自定义负载均衡
            DynamicLoadBalanceRule rule = new DynamicLoadBalanceRule();
            rule.initWithNiwsConfig(clientConfig);
            rule.setRuleService(ruleService);

            // 自定义服务列表
            DynamicServerList serverList = new DynamicServerList();
            serverList.initWithNiwsConfig(clientConfig);
            serverList.setServerLoader(serverLoader);

            // 使用spring cloud定义的
            ServerListFilter serverListFilter = getInstance(serviceId, ServerListFilter.class);
            ServerListUpdater serverListUpdater = getInstance(serviceId, ServerListUpdater.class);
            IPing ping = getInstance(serviceId, IPing.class);
            loadBalancer = new ZoneAwareLoadBalancer<>(clientConfig, rule, ping, serverList,
                    serverListFilter, serverListUpdater);

            clientMap.put(serviceId, loadBalancer);
        }
        return loadBalancer;
    }

    private <T> T getInstance(String serviceId, Class<T> clazz) {
        return this.clientFactory.getInstance(serviceId, clazz);
    }

    public void setRuleService(LoadBalancerRuleService ruleService) {
        this.ruleService = ruleService;
    }

    public void setServerLoader(ServerLoader serverLoader) {
        this.serverLoader = serverLoader;
    }
}
